home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / Apple II / Essentials / AppleScanGS / BoxCtrl.DefProc.aii < prev    next >
Encoding:
Text File  |  1990-05-27  |  52.8 KB  |  2,040 lines  |  [TEXT/MPS ]

  1.                 case    obj
  2.                 case    on
  3.                 PRINT    PUSH,OFF
  4.                 INCLUDE    'BoxCtrl.DefProc.mac'
  5.                 PRINT    POP
  6.  
  7. *******************************************************************************
  8. * BoxCtl CDEFProc
  9. *
  10. * (C)  Copyright Apple Computer, Inc. 1988
  11. * All rights reserved.
  12. *
  13. * by Keith Rollin
  14. * September    1, 1988
  15. *
  16. * This is a    Custom Control for the Apple IIGS. It is similar in    appearance
  17. * and action to    the    'resize' box you get when clicking on an object    in GS Draw
  18. * or MacDraw.
  19. *
  20. * The Control is essentially a frame with 4    or 8 grow knobs    on the corners
  21. * and/or edges.    Dragging on    any    of these knobs will    grow the control. Dragging
  22. * on the frame will    move the entire    control    (like moving a window).    A flag can
  23. * be set so    that the control will be dragged if    the    user clicks    in the interior
  24. * of the control as    well. Part codes for the knobs and frame are listed    below.
  25. *
  26. * Snapping the rectangle's coordinates to a grid is also supported. The
  27. * rectangle    is snapped to the nearest point    on the grid. This effectively means
  28. * that I perform rounding, and not truncating.
  29. *
  30. * The frame    of the control is the rectangle    passed to NewControl. The size of
  31. * the knobs    and    the    size of    the    grid are passed    in ctlValue. The 'interior drag
  32. * flag' is passed in ctlFlags. See below for details.
  33. *
  34. * Color    is supported. Currently, only two colors are used: one for the frame,
  35. * and one for the knobs. The default colors    are    black.
  36. *
  37. *
  38. *
  39. *
  40. * Modification History:
  41. *
  42. *    v1.0a1    02-Apr-88    kaar    New    Today
  43. *    v1.0a2    04-Apr-88    kaar    Changed    part codes.    Defined    CtlData    to point
  44. *                                to a data block. Added edge    knobs. Grid    can
  45. *                                now    be rectangular.    Knob rectangles    no longer
  46. *                                part of    control    (created on    the    fly). Added
  47. *                                new    flags to ctlFlag. CtlValue now contains
  48. *                                only the size of the knobs.
  49. *    v1.0a3    07-Apr-88    kaar    Removed    dependance on Direct Page from the
  50. *                                application    (now uses the stack). Responds to
  51. *                                Hilite(255).
  52. *    V1.0a4    08-Apr-88    kaar    Added support for when Param1/2    are    null.
  53. *    V1.0B1    23-Apr-88    kaar    Fixed some bugs. Checked for gridsizes of 0
  54. *                                and    1. Called InvalRect    in DragCtl.
  55. *    V2.0B2    08-Jun-88    kaar    Cleaned    up the code    some in    response to    a
  56. *                                code review. Version number    bumped to 2.0 to
  57. *                                reflect    existance of simpler 1.0 version for
  58. *                                a technote.    Added support for fCtlTie in the
  59. *                                owner window's frame flags. Improved perfor-
  60. *                                mance and legibility of    Snap2Grid routine.
  61. *    V2.0B3    08-Jul-88    kaar    Part codes changed again. It seems that    only
  62. *                                one    indicator per control is allowed. Turned
  63. *                                the    source code    upside down    and    put    it into
  64. *                                Steve Glass    format.    Implemented    some of    Dan's
  65. *                                programming    style suggestions.
  66. *    V2.0    01-Sep-88    kaar    First Release
  67. *
  68. *    V2.01    23-May-90    Greg Branche
  69. *
  70. *                                Added minHeight and minWidth parameters to allow the
  71. *                                application to define the minimum width and height of
  72. *                                the control.  This was formerly handled by the minX
  73. *                                and minY parameters.  These have been redefined so
  74. *                                that they specify the leftmost and uppermost limits
  75. *                                of the control.  The maxX and maxY parameters specify
  76. *                                the right- and bottom-most limits.
  77. *
  78. *                                Bug fixes:
  79. *
  80. *                                1)  In myDrawCtl, the code was never working
  81. *                                right that checked the current state of the
  82. *                                control to determine whether to draw the control
  83. *                                as active or inactive.  This has been modified
  84. *                                to use a flag passed in the high word of ctlParam
  85. *                                as the state indicator.  $0000 = control is active,
  86. *                                $FFFF = control is inactive.
  87. *
  88. * Version 1.0    kaar
  89. *
  90. *    Used in    Custom Control technote
  91. *
  92. *
  93. * Version 2.0    kaar
  94. *
  95. *    Release    for    Source Code    Demo Disk #1
  96. *
  97. *
  98. * Version 2.01    Greg Branche
  99. *
  100. *    Used for AppleScan.GS
  101. *
  102. *******************************************************************************
  103. *
  104. *    Part Code returned:
  105. *
  106. *            $A0    for    all    parts of the control (all parts    are    'indicators')
  107. *
  108. *
  109. *    CtlValue:    Bits  8-15:    width of grow knobs
  110. *                Bits  0- 7:    height of grow knobs
  111. *
  112. *    CtlFlag    bits:
  113. *                7 =    1 -    Control    is invisible
  114. *                  =    0 -    Control    is visible
  115. *                2 =    1 -    Has    edge knobs
  116. *                  =    0 -    Doesn't
  117. *                1 =    1 -    Has    corner knobs
  118. *                  =    0 -    Doesn't
  119. *                0 =    1 -    Clicking in    interior will drag control
  120. *                  =    0 -    Clicking in    interior does nothing
  121. *
  122. *    Data:    Contains a pointer to the following    data block.    This data
  123. *            block holds    the    following information, which is    copied to
  124. *            the    end    of the control record:
  125. *
  126. *                WORD: Min Y    when growing (top limit)
  127. *                WORD: Min X    when growing (left limit)
  128. *                WORD: Max Y    when growing (bottom limit)
  129. *                WORD: Max X    when growing (right limit)
  130. *                WORD: Min Height
  131. *                WORD: Min Width
  132. *                WORD: Spacing for Y    segment    of grid
  133. *                WORD: Spacing for X    segment    of grid
  134. *
  135. *    Color Table:
  136. *        WORD: Bits    12-15:    <reserved>
  137. *                     8-11:    Knob Color
  138. *                     4-    7:    Inactive Frame/Knob    Color
  139. *                     0-    3:    Frame Color
  140. *
  141. *******************************************************************************
  142. *
  143. *    How    to use the Control:
  144. *
  145. *        Initialization and tracking    of the control work    just like any other;
  146. *        set    it up with NewControl. When    GetNextEvent returns inContent,    call
  147. *        FindControl    to see if you hit the control. If you did, call
  148. *        TrackControl.
  149. *
  150. *    Initialization:
  151. *
  152. *                pha                    ; space    for    result
  153. *                pha
  154. *                PushLong theWindow
  155. *                PushLong #theRect    ; pointer to bounding rectangle
  156. *                PushLong #0            ; no title
  157. *                PushWord #%00000111    ; vis, int will    drag, corners &    edges
  158. *                PushWord #$0503        ; Width    = 5/Height = 3
  159. *                PushLong #CtrlData    ; Pointer to additional    data
  160. *                PushLong #BoxProc    ; pointer to DefProc
  161. *                PushLong #0            ; refcon
  162. *                PushLong #0            ; use std color    table
  163. *                _NewControl
  164. *                PullLong theControl
  165. *
  166. *    theRect        dc.w    50,140,110,300
  167. *    CtrlData    dc.w    10            ; min Y
  168. *                dc.w    10            ; min X
  169. *                dc.w    100            ; max Y
  170. *                dc.w    200            ; max X
  171. *                dc.w    10            ; min height
  172. *                dc.w    16            ; min width
  173. *                dc.w    16            ; grid Y
  174. *                dc.w    32            ; grid X
  175. *
  176. *******************************************************************************
  177. **********************************************************************
  178. *                                                                     *
  179. *              Apple    IIGS Source    Code Sampler, Volume I                 *
  180. *                                                                     *
  181. *              Copyright    (c)    Apple Computer,    Inc. 1988                 *
  182. *                        All    Rights Reserved                             *
  183. *                                                                     *
  184. *             Written by    Apple II Developer Tech    Support                 *
  185. *                                                                     *
  186. *                                                                     *
  187. *                                                                     *
  188. *  ----------------------------------------------------------------     *
  189. *                                                                     *
  190. *      This program and its derivatives are licensed    only for         *
  191. *      use on Apple computers.                                         *
  192. *                                                                     *
  193. *      Works    based on this program must contain and                     *
  194. *      conspicuously    display    this notice.                             *
  195. *                                                                     *
  196. *      This software    is provided    for    your evaluation    and    to             *
  197. *      assist you in    developing software    for    the    Apple IIGS             *
  198. *      computer.                                                         *
  199. *                                                                     *
  200. *      DISCLAIMER OF    WARRANTY                                         *
  201. *                                                                     *
  202. *      THE SOFTWARE IS PROVIDED "AS IS" WITHOUT                         *
  203. *      WARRANTY OF ANY KIND,    EITHER EXPRESS OR IMPLIED,                 *
  204. *      WITH RESPECT TO ITS MERCHANTABILITY OR ITS FITNESS             *
  205. *      FOR ANY PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO             *
  206. *      THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH             *
  207. *      YOU.    SHOULD THE SOFTWARE    PROVE DEFECTIVE, YOU (AND             *
  208. *      NOT APPLE    OR AN APPLE    AUTHORIZED REPRESENTATIVE)                 *
  209. *      ASSUME THE ENTIRE    COST OF    ALL    NECESSARY SERVICING,             *
  210. *      REPAIR OR    CORRECTION.                                             *
  211. *                                                                     *
  212. *      Apple    does not warrant that the functions                         *
  213. *      contained    in the Software    will meet your requirements             *
  214. *      or that the operation    of the Software    will be                     *
  215. *      uninterrupted    or error free or that defects in the             *
  216. *      Software will    be corrected.                                     *
  217. *                                                                     *
  218. *      SOME STATES DO NOT ALLOW THE EXCLUSION                         *
  219. *      OF IMPLIED WARRANTIES, SO    THE    ABOVE EXCLUSION    MAY                 *
  220. *      NOT APPLY    TO YOU.     THIS WARRANTY GIVES YOU SPECIFIC             *
  221. *      LEGAL    RIGHTS AND YOU MAY ALSO    HAVE OTHER RIGHTS                 *
  222. *      WHICH    VARY FROM STATE    TO STATE.                                 *
  223. *                                                                     *
  224. *                                                                     *
  225. **********************************************************************
  226.                 eject
  227. ;-------------------------------------------
  228. ;
  229. ; --- Constants
  230. ;
  231. ; --- Stack    Frame/Local    Direct Page    usage
  232. ;
  233.  
  234. OrigD            equ        1                        ; caller's saved direct page register
  235. OrigB            equ        OrigD+2                    ; caller's saved data bank register
  236. work            equ        OrigB+1                    ; general use work space
  237. CtlPtr            equ        work+4                    ; pointer to control record
  238. RtnAddr            equ        CtlPtr+4                ; RTL address back to Control Manager
  239. theCtlHandle    equ        RtnAddr+3                ; handle to    control    record
  240. CtlParam        equ        theCtlHandle+4            ; add'l parameter passed to DefProc
  241. CtlCode            equ        CtlParam+4                ; operation    to perform
  242. ReturnValue        equ        CtlCode+2                ; space    for    return value to    Ctl    Mgr.
  243.  
  244. ;
  245. ; --- Offsets for my control record
  246. ;
  247.  
  248. oCtlMinY        equ        octlColor+4
  249. oCtlMinX        equ        oCtlMinY+2
  250. oCtlMaxY        equ        oCtlMinX+2
  251. oCtlMaxX        equ        oCtlMaxY+2
  252. oCtlMinHeight    equ        oCtlMaxX+2
  253. oCtlMinWidth    equ        oCtlMinHeight+2
  254. oCtlGridY        equ        oCtlMinWidth+2
  255. oCtlGridX        equ        oCtlGridY+2
  256. oCtlSize        equ        oCtlGridX+2
  257.  
  258. ;
  259. ; --- Part codes for my    control
  260. ;
  261.  
  262. BoxCtlPart        equ        $A0                        ; This is returned to the app.
  263.  
  264. FramePart        equ        $01                        ; These    are    used internally    to tell
  265. InteriorPart    equ        $02                        ; 'myDragCtl' what part    of the
  266. ULPart            equ        $03                        ; control we are dragging.
  267. TopPart            equ        $04
  268. URPart            equ        $05
  269. RightPart        equ        $06
  270. LLPart            equ        $07
  271. BottomPart        equ        $08
  272. LRPart            equ        $09
  273. LeftPart        equ        $0A
  274.  
  275.  
  276. ;
  277. ; --- Masks    for    ctlFlags
  278. ;
  279.  
  280. dragIntMask        equ        %00000001                ; if set, let user drag    on interior
  281. knobCornerMask    equ        %00000010                ; if set, draw knobs on    the    corners
  282. knobEdgeMask    equ        %00000100                ; if set, draw knobs on    the    edges
  283. visMask            equ        ctlInVis
  284.  
  285.                 EJECT
  286. *******************************************************************************
  287. *
  288. CtlData            RECORD
  289. *
  290. * Description:    Storage    for    CDEF
  291. *
  292. *
  293. * External Refs:    NONE
  294. *
  295. * Entry    Points:    NONE
  296. *
  297. *******************************************************************************
  298.  
  299. deltaX            ds.b    2                        ; used when    growing    the    control
  300. deltaY            ds.b    2
  301. ColorPtr        ds.b    4                        ; pointer to actual    color table    to use
  302. theParam        ds.b    4                        ; copy of CtlParam passed on stack
  303. dragPart        ds.b    2                        ; internal part    of control hit
  304.  
  305. myCtlRect        ds.b    8                        ; copy of CtlRect in control record
  306. myCtlGridY        ds.b    2                        ; copy of CtlGridY
  307. myCtlGridX        ds.b    2                        ; copy of CtlGridX
  308.  
  309. FrameHeight        ds.b    2
  310. FrameWidth        ds.b    2
  311.  
  312. knobUL            ds.b    8                        ; This space is    used to    store the
  313. knobTop            ds.b    8                        ; rectangles that define the grow
  314. knobUR            ds.b    8                        ; knobs    on the control.    They are
  315. knobRight        ds.b    8                        ; created as needed, and are not
  316. knobLR            ds.b    8                        ; stored in    the    control    record.
  317. knobBottom        ds.b    8
  318. knobLL            ds.b    8
  319. knobLeft        ds.b    8
  320.  
  321. StdColorTable    dc.b    $C0                        ; grey inact frame,    blk    normal frame
  322.                 dc.b    $00                        ; black    knobs
  323. StdCtlData        dc.w    10,10,200,640,0,0        ; min 10,10; max 200,640; no grid
  324. oldPenState        ds.b    $32                        ; storage for old pen state.
  325.  
  326. GreyPattern        dc.b    $CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
  327.                 dc.b    $CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
  328.                 dc.b    $CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
  329.                 dc.b    $CC,$CC,$CC,$CC,$CC,$CC,$CC,$CC
  330.  
  331.                 ENDR
  332.  
  333.                 EJECT
  334. *******************************************************************************
  335. *
  336. BoxProc            PROC    Export
  337. *
  338. * Description:    Main Routine for Custom    Control.
  339. *
  340. *
  341. * Inputs:    On entry, the parameters are passed    to us on the stack.
  342. *
  343. *    |                    | Previous Contents
  344. *    |-------------------|
  345. *    |     ReturnValue    | LONG - Space for return value
  346. *    |-------------------|
  347. *    |     CtlCode        | WORD - operation to perform
  348. *    |-------------------|
  349. *    |     CtlParam        | LONG - add'l parameter
  350. *    |-------------------|
  351. *    |     theCtlHandle    | LONG - Handle    to control record
  352. *    |-------------------|
  353. *    |     RtnAddr        | 3    BYTES -    RTL    address
  354. *    |-------------------|
  355. *    |                    | <-- Stack    pointer
  356. *
  357. * Outputs:    Put    something into ReturnValue,    pull off the parameters,
  358. *    and    return to the Control Manager.
  359. *
  360. *    |                    | Previous Contents
  361. *    |-------------------|
  362. *    |     ReturnValue    | LONG - Space for return value
  363. *    |-------------------|
  364. *    |     RtnAddr        | 3    BYTES -    RTL    address
  365. *    |-------------------|
  366. *    |                    | <-- Stack    pointer
  367. *
  368. * External Refs:
  369.                 import    InitCtlData
  370.                 import    myDrawCtl
  371.                 import    myTestCtl
  372.                 import    myInitCtl
  373.                 import    myDragCtl
  374.                 import    myNewValue
  375.                 import    mySetParams
  376.                 import    myRecSize
  377.                 import    Null
  378. *
  379. * Entry    Points:    NONE
  380. *
  381. *******************************************************************************
  382.                 with    CtlData
  383.  
  384. ;
  385. ; We are going to be using the stack as    our    direct page    for    the
  386. ; custom control. The equates listed at    the    beginning of the custom
  387. ; control (right after the pageful of comments that    explain    it)
  388. ; describe the layout of the stack frame.
  389. ;
  390. ; The way we set up    the    stack frame    as our direct page is by first
  391. ; saving the old contents of the DP    register, transfering the stack
  392. ; pointer to the accumulator, and then transferring    that to    the    DP
  393. ; register.    We also    save the contents of the Data Bank Register    and
  394. ; reset    it to the Program Bank Register    so that    we don't have to
  395. ; use 3-byte long addressing anywhere. We will restore both    of these
  396. ; registers    when we    leave the custom control.
  397. ;
  398.  
  399.                 pha                                ; push on some room    for    'CtlPtr'
  400.                 pha
  401.                 pha                                ; push on some room    for    'work'
  402.                 pha
  403.  
  404.                 phb                                ; save the Data    Bank register
  405.                 phd                                ; save the Direct Page register
  406.  
  407.                 phk                                ; switch data bank to program bank
  408.                 plb
  409.                 tsc                                ; switch Direct    Page into stack
  410.                 tcd
  411.  
  412.                 jsr        InitCtlData                ; init some    handy data
  413.  
  414.                 lda        <CtlCode                ; get routine #    to call
  415.                 cmp        #recSize+1                ; we only know of 12 CtlCodes
  416.                 blt        ShiftIt
  417.                 lda        #6                        ; force    unknown    codes to null events
  418. ShiftIt
  419.                 asl        a
  420.                 tax
  421.                 jsr        (CtlTable,x)
  422.  
  423.                 sta        <ReturnValue            ; save the return value
  424.                 stx        <ReturnValue+2
  425.  
  426. ;
  427. ; The Return Value has been    stored on the stack, and it    is time    for    us to
  428. ; return back to the Control Manager. Before we    do so, however,    we must
  429. ; remove the parameters    that were passed to    us on the stack. We    do this
  430. ; by moving    the    RTL    address    up just    below the Return Value,    getting    the
  431. ; stack    pointer, and adding    an amount to it    so that    we point to    where
  432. ; the RTL address has been moved to. We    can    then simply    RTL    back to    the
  433. ; Control Manager, and it will pick    up the Return Value    right off of the
  434. ; stack!
  435. ;
  436.                 lda        <RtnAddr                ; move the return address up
  437.                 sta        <ReturnValue-3
  438.                 lda        <RtnAddr+1
  439.                 sta        <ReturnValue-2
  440.  
  441.                 tsc                                ; Get the stack    pointer
  442.  
  443.                 pld                                ; restore caller's Data Bank and
  444.                 plb                                ; Direct Page registers
  445.  
  446.                 clc                                ; Adjust the stack pointer to point    to
  447.                 adc        #ReturnValue-4            ; the new location of the RTL address.
  448.                 tcs                                ; Put the stack    pointer    back.
  449.  
  450.                 rtl                                ; back to the caller
  451.  
  452.  
  453. ; This is a    table of pointers to routines to be    called for specific
  454. ; CtlCodes passed to us. The 'null'    entries    are    pointers to    a
  455. ; routine that does    nothing    except return 'no error'.
  456.  
  457. CtlTable
  458.                 dc.w    myDrawCtl                ; 0    drawCtl
  459.                 dc.w    Null                    ; 1    calcCRect
  460.                 dc.w    myTestCtl                ; 2    testCtl
  461.                 dc.w    myInitCtl                ; 3    initCtl
  462.                 dc.w    Null                    ; 4    dispCtl
  463.                 dc.w    Null                    ; 5    posCtl
  464.                 dc.w    Null                    ; 6    thumbCtl
  465.                 dc.w    myDragCtl                ; 7    dragCtl
  466.                 dc.w    Null                    ; 8    autoTrack
  467.                 dc.w    myNewValue                ; 9    newValue
  468.                 dc.w    mySetParams                ;10    setParams
  469.                 dc.w    myInitCtl                ;11    moveCtl
  470.                 dc.w    myRecSize                ;12    recSize
  471.  
  472.                 ENDP
  473.  
  474.                 EJECT
  475. *******************************************************************************
  476. *
  477. myDrawCtl        PROC
  478. *
  479. * Description:    Draw control command.
  480. *
  481. *
  482. * Inputs:    NONE
  483. *
  484. * Outputs:    NONE
  485. *
  486. * External Refs:
  487.                 import    CalcCorners
  488.                 import    SetMyPen
  489. *
  490. * Entry    Points:    NONE
  491. *
  492. *******************************************************************************
  493.                 with    CtlData
  494.  
  495. ; figure out the coordinates of    the    grow knobs.
  496.  
  497.                 jsr        CalcCorners
  498.  
  499. ; Save the pen state, as we'll be changing it a lot.
  500.  
  501.                 PushLong #oldPenState
  502.                 _GetPenState
  503.  
  504. ; Set the correct width    of the pen for the mode    we are in.
  505.  
  506.                 jsr        SetMyPen
  507.  
  508. ;
  509. ; Set the local    variable 'ActivFlag' to    indicate how to    draw the
  510. ; control. We draw it inactive if a) the Hilite    value is 255, or b)
  511. ; the owner    window is inactive and fCtrlTie    is set.
  512. ;
  513.                 ldy        #octlHilite                ; are we inactive?
  514.                 lda        [<CtlPtr],y
  515.                 and        #$00FF
  516.                 cmp        #$00FF
  517.                 beq        DrawInactive            ; yes, so clear    ActivFlag
  518.  
  519. ; At this point, the control can potentially be    drawn as an    active
  520. ; control. But this    can    only happen    if the window is active, or    is
  521. ; inactive but with    the    fCtlTie    flag clear.
  522.  
  523.                 lda        CtlParam+2                ; get the flag passed by the Control Manager
  524.                 bmi        DrawInactive            ; $FFFF = inactive
  525.  
  526. DrawActive        lda        #1
  527.                 sta        ActivFlag
  528.                 bra        SetColorTable
  529.  
  530. DrawInactive    stz        ActivFlag
  531.  
  532. ; Put the color    table pointer into a  Direct page location.
  533.  
  534. SetColorTable
  535.                 lda        ColorPtr
  536.                 sta        <work
  537.                 lda        ColorPtr+2
  538.                 sta        <work+2
  539.  
  540. ;
  541. ; See if the control is    active or not, and set the color
  542. ; accordingly.
  543. ;
  544.  
  545.                 lda        ActivFlag
  546.                 bne        SetFrameColor
  547.  
  548.                 lda        [<work]                    ; YES -    so we are. Use the inactive
  549.                 lsr        a                        ; pattern for this.
  550.                 lsr        a
  551.                 lsr        a
  552.                 lsr        a
  553.                 and        #$000f
  554.                 pha
  555.                 _SetSolidPenPat
  556.  
  557.                 bra        DrawFrame
  558.  
  559. SetFrameColor
  560.                 lda        [<work]                    ; get the color    for    the    frame from
  561.                 and        #$000f                    ; the color    table and use it.
  562.                 pha
  563.                 _SetSolidPenPat
  564.  
  565. DrawFrame
  566.                 PushLong #myCtlRect                ; draw the frame of    the    control
  567.                 _FrameRect
  568.  
  569. ;
  570. ; See if the control is    active or not, and set the color accordingly. If
  571. ; we so    chose we could even    decide not to draw knobs on    an inactive    sizer.
  572. ; This is similar to the scrollbar defproc no drawing the thumb    on an
  573. ; inactive scrollbar.
  574. ;
  575.  
  576.                 lda        ActivFlag
  577.                 beq        DrawKnobs                ; it's inactive; keep that pattern
  578.  
  579.                 lda        [<work]                    ; get the color    of the knobs from
  580.                 xba                                ; the color    table and set it.
  581.                 and        #$000f
  582.                 pha
  583.                 _SetSolidPenPat
  584.  
  585. DrawKnobs
  586.                 ldy        #octlFlag                ; do we    need corner    knobs?
  587.                 lda        [<CtlPtr],y
  588.                 and        #knobCornerMask
  589.                 beq        ckEdges                    ; no, so check for edge    knobs.
  590.  
  591.                 PushLong #knobUL                ; yes, so draw them
  592.                 _PaintRect
  593.  
  594.                 PushLong #knobUR
  595.                 _PaintRect
  596.  
  597.                 PushLong #knobLL
  598.                 _PaintRect
  599.  
  600.                 PushLong #knobLR
  601.                 _PaintRect
  602.  
  603. ckEdges
  604.                 ldy        #octlFlag                ; do we    need edge knobs?
  605.                 lda        [<CtlPtr],y
  606.                 and        #knobEdgeMask
  607.                 beq        done                    ; no, so leave
  608.  
  609.                 PushLong #knobTop                ; yes, so draw them.
  610.                 _PaintRect
  611.  
  612.                 PushLong #knobRight
  613.                 _PaintRect
  614.  
  615.                 PushLong #knobBottom
  616.                 _PaintRect
  617.  
  618.                 PushLong #knobLeft
  619.                 _PaintRect
  620.  
  621. done
  622.                 PushLong #oldPenState            ; clean    up after ourselves.
  623.                 _SetPenState
  624.  
  625.                 lda        #0
  626.                 tax
  627.  
  628.                 rts
  629.  
  630. ActivFlag        ds.b    2
  631.  
  632.                 ENDP
  633.  
  634.                 EJECT
  635. *******************************************************************************
  636. *
  637. myTestCtl        PROC
  638. *
  639. * Description:    Hit    test command. This routine checks to see if    we have
  640. *    chosen the ability to drag the control when    we click in
  641. *    the    interior or    not. If    so,    then we    will always    return
  642. *    our    partcode (BoxCtlPart = $A0). If    not, then we only
  643. *    return our partcode    if we click    on the frame or    a knob.
  644. *
  645. *
  646. * Inputs:    NONE
  647. *
  648. * Outputs:    A =    Part code hit
  649. *
  650. * External Refs:
  651.                 import    TestFrame
  652. *
  653. * Entry    Points:    NONE
  654. *
  655. *******************************************************************************
  656.                 with    CtlData
  657.  
  658.                 jsr        TestFrame
  659.                 cmp        #noPart                    ; hit anything?
  660.                 beq        exit                    ; no - return nothing
  661.                 lda        #BoxCtlPart                ; yes -    return our partcode
  662. exit
  663.                 ldx        #0                        ; high byte    of return value    always $00
  664.                 rts
  665.  
  666.                 ENDP
  667.  
  668.                 EJECT
  669. *******************************************************************************
  670. *
  671. myInitCtl        PROC
  672. *
  673. * Description:    Called to initialize my    custom fields of the control
  674. *    record.    It calles mySetParams to handle    the    data that
  675. *    is pointed to by the Data/Params field,    and    makes sure
  676. *    that the corners of    the    rectangle lie on the grid.
  677. *
  678. *
  679. * Inputs:    NONE
  680. *
  681. * Outputs:    NONE
  682. *
  683. * External Refs:
  684.                 import    mySetParams
  685.                 import    Snap2Grid
  686.                 import    SetCtlRect
  687.                 import    InitCtlData
  688. *
  689. * Entry    Points:    NONE
  690. *
  691. *******************************************************************************
  692.                 with    CtlData
  693.  
  694. ; First, set up    some fields    based on the value of Param. This is
  695. ; a    pointer    to some    additional data, so    what SetParams does    is
  696. ; copy that    into our control record.
  697.  
  698.                 jsr        mySetParams
  699.                 jsr        InitCtlData
  700.  
  701. ; Next,    make sure the edges    of the control are aligned to a    grid.
  702.  
  703.                 ldx        #^myCtlRect
  704.                 lda        #myCtlRect
  705.                 jsr        Snap2Grid
  706.  
  707.                 jsr        SetCtlRect
  708.  
  709.                 lda        #0                        ; return nothing
  710.                 txa
  711.  
  712.                 rts
  713.                 ENDP
  714.  
  715.                 EJECT
  716. *******************************************************************************
  717. *
  718. myDragCtl        PROC
  719. *
  720. * Description:    Drag command. We hit something.    Determine what it was and
  721. *    drag it    around the screen. If we hit the frame,    then drag
  722. *    the    whole control. If we hit a knob, then we grow the
  723. *    control    (just like growing a window).
  724. *
  725. *
  726. * Inputs:    NONE
  727. *
  728. * Outputs:    NONE
  729. *
  730. * External Refs:
  731.                 import    SetMyPen
  732.                 import    Snap2Grid
  733.                 import    myDrawCtl
  734.                 import    FindPart
  735.                 import    SetCtlRect
  736. *
  737. * Entry    Points:    NONE
  738. *
  739. *******************************************************************************
  740.                 with    CtlData
  741.  
  742.                 PushLong #oldPenState            ; save drawing state, as we    change it
  743.                 _GetPenState
  744.  
  745.                 ldx        #6                        ; copy original control rect to drag_rect
  746. @loop
  747.                 lda        myCtlRect,x
  748.                 sta        drag_rect,x
  749.                 dex
  750.                 dex
  751.                 bpl        @loop
  752.  
  753.                 ldy        #oCtlMaxX                ; get local    copies of the maximum
  754.                 ldx        #6                        ; and minimum dimensions.
  755. loop0010        lda        [<CtlPtr],y
  756.                 sta        limitRect,x
  757.                 dey
  758.                 dey
  759.                 dex
  760.                 dex
  761.                 bpl        loop0010
  762.  
  763.                 ldy        #oCtlMinHeight
  764.                 lda        [<CtlPtr],y
  765.                 sta        MinHeight
  766.                 iny
  767.                 iny
  768.                 lda        [<CtlPtr],y
  769.                 sta        MinWidth
  770.  
  771. ; Get the portRect of the window that owns this    control. This rectangle
  772. ; will be used to control the limits of    dragging.
  773.  
  774.                 ldy        #octlOwner                ; get the pointer to the control's
  775.                 lda        [<CtlPtr],y                ; owning window    into 'work'
  776.                 sta        <work
  777.                 iny
  778.                 iny
  779.                 lda        [<CtlPtr],y
  780.                 sta        <work+2
  781.  
  782.                 ldy        #oportRect+6            ; copy the PortRect    of the window
  783.                 ldx        #6                        ; out of its GrafPort into slopRect.
  784. loop400            lda        [<work],y
  785.                 sta        slopRect,x
  786.                 dey
  787.                 dey
  788.                 dex
  789.                 dex
  790.                 bpl        loop400
  791.  
  792. ; Now we adjust slopRect to account for the width of the knobs
  793.  
  794.                 ldy        #octlValue                ; get the height of the knobs
  795.                 lda        [<CtlPtr],y
  796.                 and        #$00ff
  797.                 pha
  798.                 clc
  799.                 adc        slopRect
  800.                 sta        slopRect
  801.                 lda        slopRect+4
  802.                 sec
  803.                 sbc        1,s
  804.                 sta        slopRect+4
  805.                 pla                                ; remove from stack
  806.  
  807.                 lda        [<CtlPtr],y                ; get the width of the knobs
  808.                 xba
  809.                 and        #$00ff
  810.                 pha
  811.                 clc
  812.                 adc        slopRect+2
  813.                 sta        slopRect+2
  814.                 lda        slopRect+6
  815.                 sec
  816.                 sbc        1,s
  817.                 sta        slopRect+6
  818. ;                                                ; leave on stack as space for result of GetNextEvent
  819.  
  820. ;                pha                                ; has the mouse    been lifted    up?
  821.                 PushWord #mUpMask                ; ask for any such events
  822.                 PushLong #TrackEvent
  823.                 _GetNextEvent
  824.                 pla
  825.  
  826.                 lda        TrackEvent+owhat
  827.                 cmp        #mouseUpEvt                ; was there    a mouse    up event?
  828.                 bne        mDown                    ; no - so start    tracking
  829.                 brl        done                    ; yes -    so leave
  830.  
  831. mDown
  832.                 PushLong #TrackEvent+owhere
  833.                 _GlobalToLocal
  834.  
  835.                 lda        TrackEvent+owhere
  836.                 sta        OldMouse                ; FindPart likes the mouse Position
  837.                 sta        theParam                ; in 'theParam'
  838.                 lda        TrackEvent+owhere+2
  839.                 sta        OldMouse+2
  840.                 sta        theParam+2
  841.  
  842.                 jsr        FindPart                ; what did we hit? (returns    internal
  843.                 sta        dragPart                ;    partcode number).
  844.  
  845.                 cmp        #InteriorPart+1            ; what part    did    we hit?
  846.                 bge        GrowFrame                ; some knob    - grow the control
  847.                 brl        DragFrame                ; interior or frame    - move the control
  848.  
  849. ;
  850. ; This part    of the program is called when we detect    that we    have clicked on
  851. ; a    grow knob. It tracks the motions of    the    mouse, and grows/draws the
  852. ; control appropriately.
  853. ;
  854. GrowFrame
  855.                 PushWord #2                        ; set us to    XOR    mode. This is for the
  856.                 _SetPenMode                        ; rubber-banding effect    of growing.
  857.  
  858.                 jsr        SetMyPen                ; set my pen's width
  859.  
  860.                 PushLong #GreyPattern            ; grow with    a grey pattern
  861.                 _SetPenPat
  862.  
  863. ; validate the min and max values. the min values must be at least $4.
  864. ; if not, they are set there. the max values must be at    least as large
  865. ; as the min values. if    not, they are set to $FFFF
  866.  
  867.                 lda        #4
  868.                 cmp        MinWidth
  869.                 blt        ckMinY
  870.                 sta        MinWidth
  871.  
  872. ckMinY            cmp        MinHeight
  873.                 blt        ckMaxX
  874.                 sta        MinHeight
  875.  
  876. ckMaxX            lda        limitRect+6
  877.                 sec
  878.                 sbc        MinWidth
  879.                 cmp        limitRect+2
  880.                 bge        ckMaxY
  881. ChgX            lda        #$FFFF
  882.                 sta        limitRect+6
  883.  
  884. ckMaxY            lda        limitRect+4
  885.                 sec
  886.                 sbc        MinHeight
  887.                 cmp        limitRect
  888.                 bge        doneCk
  889. ChgY            lda        #$FFFF
  890.                 sta        limitRect+4
  891. doneCk
  892.                  lda        myCtlRect+4            ; get lower boundary
  893.                 sec
  894.                 sbc        MinHeight            ; calculate theoretical upper boundary
  895.                 sta        minRect                ; store it as upper limit
  896.                 lda        myCtlRect            ; get upper boundary
  897.                 clc
  898.                 adc        MinHeight            ; calculate
  899.                 sta        minRect+4            ; store as lower limit
  900.                 lda        myCtlRect+6            ; get right boundary
  901.                 sec
  902.                 sbc        MinWidth            ; calculate
  903.                 sta        minRect+2            ; store as left limit
  904.                 lda        myCtlRect+2            ; get left boundary
  905.                 clc
  906.                 adc        MinWidth            ; calculate
  907.                 sta        minRect+6            ; store as right limit
  908.  
  909. ;
  910. ; We grow the control with the following algorithm.    First, setup by:
  911. ;
  912. ;  1. saving the current mouse postion in 'NewMouse',
  913. ;  2. aligning 'NewMouse' to the grid, and
  914. ;  3. making a working copy    of the control's rectangle in 'drag_rect'.
  915. ;
  916. ; We then enter    the    main loop:
  917. ;
  918. ;  4. Draw a copy of the rubber-banding    rectangle.
  919. ;  5. Check    the    mouse button. If it    is up, goto    #12
  920. ;  6. Put the position of the mouse    into 'NewerMouse'. Align it    to grid.
  921. ;  7. Check    it against 'NewMouse'. If it hasn't changed, goto #5.
  922. ;  8. Erase    the    old    rubber-Band.
  923. ;  9. Calculate    the    new    rectangle and put it into 'drag_rect'
  924. ; 10. Move 'NewerMouse'    into 'NewMouse'
  925. ; 11. Goto #4
  926. ;
  927. ; The growing is all done. Clean up    and    leave.
  928. ;
  929. ; 12. Erase    the    rubber band.
  930. ; 13. Erase    the    control.
  931. ; 14. Invalidate the area under    the    control
  932. ; 15. Make drag_rect the new boundary of the control
  933. ; 16. Say goodnite,    Gracie.
  934. ;
  935.  
  936.                 lda        OldMouse
  937.                 sta        NewMouse
  938.                 lda        OldMouse+2
  939.                 sta        NewMouse+2
  940.  
  941.                 ldx        #^NewMouse                ; make sure    we are on the grid!!!
  942.                 lda        #NewMouse
  943.                 jsr        Snap2Grid
  944.  
  945. DrawLoop
  946.                 PushLong #drag_rect                ; draw the rubber-band
  947.                 _FrameRect
  948.  
  949. WaitLoop
  950.                 pha                                ; has the mouse    been lifted    up?
  951.                 PushWord #mUpMask                ; ask for any such events
  952.                 PushLong #TrackEvent
  953.                 _GetNextEvent
  954.                 pla
  955.  
  956.                 lda        TrackEvent+owhat
  957.                 cmp        #mouseUpEvt
  958.                 beq        done                    ; mouse    up occured - so    leave.
  959.  
  960.                 lda        TrackEvent+owhere        ; mouse    still down.    copy it    to
  961.                 sta        NewerMouse                ; NewerMouse
  962.                 lda        TrackEvent+owhere+2
  963.                 sta        NewerMouse+2
  964.  
  965.                 PushLong #NewerMouse            ; convert it to    window coordinates.
  966.                 _GlobalToLocal
  967.  
  968.                 ldx        #^NewerMouse            ; make sure    the    new    position is    on
  969.                 lda        #NewerMouse                ; the grid.
  970.                 jsr        Snap2Grid
  971.  
  972.                 lda        NewerMouse                ; See if the mouse position    moved. We
  973.                 cmp        NewMouse                ; only redraw the rubber-band if it    did.
  974.                 bne        ReDraw                    ; It did - redraw the rubber-band
  975.                 lda        NewerMouse+2
  976.                 cmp        NewMouse+2
  977.                 beq        WaitLoop                ; No movement -    check button state
  978.  
  979. ReDraw
  980.                 PushLong #drag_rect                ; erase    the    old    rubber band
  981.                 _FrameRect
  982.  
  983.                 lda        NewerMouse                ; copy NewerMouse for next loop
  984.                 sta        NewMouse
  985.                 sec                                ; and update deltaXY for AdjFrameRect
  986.                 sbc        OldMouse
  987.                 sta        deltaY
  988.  
  989.                 lda        NewerMouse+2
  990.                 sta        NewMouse+2
  991.                 sec
  992.                 sbc        OldMouse+2
  993.                 sta        deltaX
  994.  
  995.                 jsr        AdjFrameRect            ; adjust for drawing the new rect
  996.  
  997.                 brl        DrawLoop                ; redraw the rubber-band
  998.  
  999. done
  1000.                 PushLong #drag_rect                ; erase    the    rubber band
  1001.                 _FrameRect
  1002.  
  1003.                 PushLong #myCtlRect                ; erase    the    control
  1004.                 _EraseRect
  1005.  
  1006.                 PushLong #myCtlRect                ; invalidate the stuff under it
  1007.                 _InvalRect
  1008.  
  1009.                 brl        Exit
  1010. ;
  1011. ; This part    of the program is called when we have clicked on either    the
  1012. ; frame    or the interior. It    calls dragrect to move an outline of the
  1013. ; control around.
  1014. ;
  1015.  
  1016. DragFrame
  1017.  
  1018. ;
  1019. ; Use dragRect to drag an outline of the control around    the
  1020. ; screen for me.
  1021. ;
  1022.                 pha                                ; space    for    result
  1023.                 pha
  1024.                 PushLong #DragDraw                ; no action    proc
  1025.                 PushLong #GreyPattern            ; drag pattern
  1026.                 PushLong OldMouse                ; starting location    of mouse
  1027.                 PushLong #drag_rect                ; outline to drag
  1028.                  PushLong #limitRect                ; rect defining limits
  1029.                 PushLong #slopRect                ; slopRect
  1030.                 PushWord #%00101000                ; custom drag flag,    ReturnRect flag
  1031.                 _DragRect
  1032.  
  1033.                 pla                                ; pull off and discard the deltas
  1034.                 pla
  1035.  
  1036.                 PushLong #myCtlRect                ; erase    the    control    in its old pos'n
  1037.                 _EraseRect
  1038.  
  1039.                 PushLong #myCtlRect                ; invalidate the stuff under it
  1040.                 _InvalRect
  1041.  
  1042.                 ldx        #^drag_rect                ; align    the    new    rectangle to the grid.
  1043.                 lda        #drag_rect
  1044.                 jsr        Snap2Grid
  1045.  
  1046. Exit
  1047.                 ldy        #6                        ; copy over    the    new    control    frame
  1048. loop200            lda        drag_rect,y
  1049.                 sta        myCtlRect,y
  1050.                 dey
  1051.                 dey
  1052.                 bpl        loop200
  1053.  
  1054.                 PushLong #myCtlRect                ; Invalidate the new area under    the
  1055.                 _InvalRect                        ; control so it    will be    redrawn.
  1056.  
  1057.                 PushLong #oldPenState
  1058.                 _SetPenState                    ; clean    up QuickDraw after ourselves.
  1059.  
  1060.                 jsr        SetCtlRect                ; copy new rect    into control record
  1061.  
  1062.                 lda        #-1                        ; Say that we handled it
  1063.                 tax
  1064.  
  1065.                 rts
  1066.  
  1067. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1068. ;
  1069. ; Called by    DragRect to    draw the rectangle of the control. I draw the outline
  1070. ; myself so    that I can align it    to my own grid.    The    normal aligning    of the
  1071. ; rectangle    to the grid    only aligns    to powers of 2.    I align    to anything.
  1072. ;
  1073. ; When this    routine    is called, the stack looks like    this:
  1074. ;
  1075. ;    PUSH:WORD -    delta X
  1076. ;    PUSH:WORD -    delta Y
  1077. ;    PUSH:BYTE[3] - return address
  1078. ;
  1079. ; However, since I set the ReturnRect flag,    I can ignore the deltas    passed to
  1080. ; me, and use drag_rect    directly. I    make a copy    of it, make    sure that it is
  1081. ; aligned to the grid, draw    it,    remove the parameters, and return to the
  1082. ; control manager.
  1083. ;
  1084.  
  1085. DragDraw
  1086.  
  1087. RTLAddr            equ        1
  1088. DY                equ        RTLAddr+3
  1089. DX                equ        DY+2
  1090.  
  1091.                 ldx        #6                        ; make a copy of the rectangle that
  1092. loop500            lda        drag_rect,x                ; _DragRect    is passing to us. We are
  1093.                 sta        draw_rect,x                ; going    to modify it so    that it    is
  1094.                 dex                                ; aligned to the grid.
  1095.                 dex
  1096.                 bpl        loop500
  1097.  
  1098.                 ldx        #^draw_rect                ; align    the    new    rectangle to the grid.
  1099.                 lda        #draw_rect
  1100.                 jsr        Snap2Grid
  1101.  
  1102. DrawOutline
  1103.                 PushLong #draw_rect
  1104.                 _FrameRect
  1105.  
  1106. ExitDragDraw
  1107.                 lda        1,s                        ; move the RTL address back    up
  1108.                 sta        5,s
  1109.                 lda        2,s
  1110.                 sta        6,s
  1111.  
  1112.                 pla                                ; remove the parameters    (DX, DY)
  1113.                 pla
  1114.  
  1115.                 rtl                                ; back to dragRect!!
  1116.  
  1117. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1118. ;
  1119. ; Called by    the    routine    that grows the control with    a rubber-band
  1120. ; sort of thing. It    uses the part code we hit as an    index into
  1121. ; a    table. This    table contains a list of offsets into the
  1122. ; 4    words of drag_rect.    It reads in    a pair of these    offsets    and
  1123. ; uses them    to modify the appropriate X/Y coordinates with
  1124. ; deltaY and deltaX. DeltaY    and    deltaX are set up by the
  1125. ; rubber-banding routine.
  1126.  
  1127. AdjFrameRect
  1128.                 ldx        #6
  1129. loop380            lda        drag_rect,x
  1130.                 sta        new_rect,x
  1131.                 dex
  1132.                 dex
  1133.                 bpl        loop380
  1134.  
  1135.                 lda        dragPart                ; get the part code    we are dragging
  1136.                 sec
  1137.                 sbc        #ULPart
  1138.                 asl        a                        ; turn it into an index.
  1139.                 asl        a
  1140.                 tax
  1141.                 lda        PtToAdj,x                ; get Y    coordinate to adjust
  1142.                 tay
  1143.                 lda        PtToAdj+2,x                ; get X    coordinate to adjust
  1144.                 tax
  1145.  
  1146. ; if the entry that    was    fetched    from the table was -1, then    that means
  1147. ; that we are making no    adjustments    in that    direction. For instance, it
  1148. ; we are dragging on the top edge knob,    we want    to adjust just the top
  1149. ; side of the rectangle, but want to leave either of the sides alone.
  1150.  
  1151.                 cpy        #-1                        ; modify the vertical coordinate
  1152.                 beq        NoChg1                    ; of choice    if necessary.
  1153.                 clc
  1154.                 lda        deltaY
  1155.                 adc        myCtlRect,y
  1156.                 sta        new_rect,y
  1157.  
  1158. NoChg1            cpx        #-1                        ; modify the horizontal    coordinate
  1159.                 beq        NoChg2                    ; of choice    if necessary.
  1160.                 clc
  1161.                 lda        deltaX
  1162.                 adc        myCtlRect,x
  1163.                 sta        new_rect,x
  1164.  
  1165. NoChg2
  1166.                 ldx        #^new_rect                ; align    the    rectangle to the grid.
  1167.                 lda        #new_rect
  1168.                 jsr        Snap2Grid
  1169.  
  1170. ; now that we have a new rectangle,    we have    to make    sure that it is    within
  1171. ; the maximum and minimum sizes    allowed.
  1172.  
  1173. ; First, we check to make sure the new rect is within the slopRect.  If not
  1174. ; we revert back to the original rect position.  This mimics the action of
  1175. ; DragRect.
  1176.  
  1177.                 pha                            ; space for result
  1178.                 pushlong #NewMouse            ; put point on stack
  1179.                 pushlong #slopRect            ; put slopRect on stack
  1180.                 _PtInRect
  1181.                 pla                            ; retrieve result
  1182.                 bne        inRect                ; yes, the new point is within slopRect
  1183.  
  1184. copyOriginal
  1185.                 ldx        #6                    ; copy original control rect to drag_rect
  1186. @loop
  1187.                 lda        myCtlRect,x
  1188.                 sta        drag_rect,x
  1189.                 dex
  1190.                 dex
  1191.                 bpl        @loop
  1192.                 rts
  1193. inRect
  1194.  
  1195. ; Now we can check to make sure the new rect is within the bounds of the
  1196. ; limit rect.  If it isn't, we peg it at the limit, again mimicking
  1197. ; DragRect.
  1198.  
  1199.                 lda        limitRect                ; outside the top limit?
  1200.                 cmp        new_rect
  1201.                 bcc        @1                        ; no...
  1202.                 sta        new_rect                ; else peg it there
  1203. @1
  1204.                 lda        limitRect+2                ; how 'bout the left limit?
  1205.                 cmp        new_rect+2
  1206.                 bcc        @2
  1207.                 sta        new_rect+2
  1208. @2
  1209.                 lda        limitRect+4
  1210.                 cmp        new_rect+4
  1211.                 bcs        @3
  1212.                 sta        new_rect+4
  1213. @3
  1214.                 lda        limitRect+6
  1215.                 cmp        new_rect+6
  1216.                 bcs        @4
  1217.                 sta        new_rect+6
  1218. @4
  1219.                  lda        minRect                ; now check the width and height for minimums
  1220.                 cmp        new_rect
  1221.                 bcs        @5
  1222.                 sta        new_rect
  1223. @5
  1224.                 lda        minRect+2
  1225.                 cmp        new_rect+2
  1226.                 bcs        @6
  1227.                 sta        new_rect+2
  1228. @6
  1229.                 lda        minRect+4
  1230.                 cmp        new_rect+4
  1231.                 bcc        @7
  1232.                 sta        new_rect+4
  1233. @7
  1234.                 lda        minRect+6
  1235.                 cmp        new_rect+6
  1236.                 bcc        @8
  1237.                 sta        new_rect+6
  1238. @8
  1239.                 ldx        #6                    ; now we can copy the new rect to drag_rect
  1240. @loop2
  1241.                 lda        new_rect,x
  1242.                 sta        drag_rect,x
  1243.                 dex
  1244.                 dex
  1245.                 bpl        @loop2
  1246.  
  1247.                 rts
  1248.  
  1249.  
  1250. PtToAdj            dc.w    0,2,0,-1,0,6,-1,6,4,6,4,-1,4,2,-1,2
  1251.  
  1252. TrackEvent        ds.b    $10
  1253.  
  1254. OldMouse        ds.b    4
  1255. NewMouse        ds.b    8
  1256. NewerMouse        ds.b    8
  1257. drag_rect        ds.b    8
  1258. draw_rect        ds.b    8
  1259. old_drag        ds.b    8
  1260. new_rect        ds.b    8
  1261. limitRect        ds.b    8
  1262. slopRect        ds.b    8
  1263. minRect            ds.b    8
  1264. MinHeight        ds.b    2
  1265. MinWidth        ds.b    2
  1266.  
  1267.                 ENDP
  1268.  
  1269.                 EJECT
  1270. *******************************************************************************
  1271. *
  1272. myNewValue        PROC
  1273. *
  1274. * Description:    Called when    the    value of the control is    to be changed.
  1275. *    The    area under the control is invalidated so that it will
  1276. *    be redrawn.
  1277. *
  1278. *
  1279. * Inputs:    NONE
  1280. *
  1281. * Outputs:    NONE
  1282. *
  1283. * External Refs:
  1284.                 import    Snap2Grid
  1285.                 import    myDrawCtl
  1286.                 import    SetCtlRect
  1287. *
  1288. * Entry    Points:    NONE
  1289. *
  1290. *******************************************************************************
  1291.                 with    CtlData
  1292.  
  1293.                 PushLong #myCtlRect                ; erase    old    control
  1294.                 _EraseRect
  1295.  
  1296.                 PushLong #myCtlRect                ; invalidate area erased
  1297.                 _InvalRect
  1298.  
  1299.                 ldx        #^myCtlRect                ; make sure    control    is on the grid
  1300.                 lda        #myCtlRect
  1301.                 jsr        Snap2Grid
  1302.  
  1303.                 jsr        SetCtlRect
  1304.  
  1305.                 lda        #0                        ; return no    value
  1306.                 tax
  1307.  
  1308.                 rts
  1309.                 ENDP
  1310.  
  1311.                 EJECT
  1312. *******************************************************************************
  1313. *
  1314. mySetParams        PROC
  1315. *
  1316. * Description:    Set    new    parameters command.    Don't set if either of them
  1317. *    are    negative.
  1318. *
  1319. *
  1320. * Inputs:    NONE
  1321. *
  1322. * Outputs:    NONE
  1323. *
  1324. * External Refs:    NONE
  1325. *
  1326. * Entry    Points:    NONE
  1327. *
  1328. *******************************************************************************
  1329.                 with    CtlData
  1330.  
  1331.                 lda        theParam                ; these    have gotta go on in    reverse
  1332.                 sta        <work+2
  1333.                 lda        theParam+2
  1334.                 sta        <work
  1335.  
  1336.                 ora        <work+2                    ; is this a    NULL pointer?
  1337.                 bne        CopyIt                    ; no - so use it
  1338.  
  1339.                 lda        #^StdCtlData            ; yes -    so set pointer to default data
  1340.                 sta        <work+2
  1341.                 lda        #StdCtlData
  1342.                 sta        <work
  1343.  
  1344. CopyIt
  1345.                 ldy        #oCtlSize-2                ; copy the data    into control record.
  1346.                 ldx        #oCtlSize-oCtlMinY-2
  1347. loop            phy
  1348.                 txy
  1349.                 lda        [<work],y
  1350.                 ply
  1351.                 sta        [<CtlPtr],y
  1352.                 dey
  1353.                 dey
  1354.                 dex
  1355.                 dex
  1356.                 bpl        loop
  1357.  
  1358.                 lda        #0                        ; return no    value
  1359.                 tax
  1360.  
  1361.                 rts
  1362.                 ENDP
  1363.  
  1364.                 EJECT
  1365. *******************************************************************************
  1366. *
  1367. myRecSize        PROC
  1368. *
  1369. * Description:    Return record size command.
  1370. *
  1371. *
  1372. * Inputs:    NONE
  1373. *
  1374. * Outputs:    A =    Size of    the    control    record to allocate.
  1375. *
  1376. * External Refs:    NONE
  1377. *
  1378. * Entry    Points:    NONE
  1379. *
  1380. *******************************************************************************
  1381.                 with    CtlData
  1382.  
  1383.                 lda        #oCtlSize                ; low word of record size
  1384.                 ldx        #0                        ; high word
  1385.  
  1386.                 rts
  1387.                 ENDP
  1388.  
  1389.                 EJECT
  1390. *******************************************************************************
  1391. *
  1392. Null            PROC
  1393. *
  1394. * Description:    Null routine. Does nothing.    Returns    no error.
  1395. *
  1396. *
  1397. * Inputs:    NONE
  1398. *
  1399. * Outputs:    NONE
  1400. *
  1401. * External Refs:    NONE
  1402. *
  1403. * Entry    Points:    NONE
  1404. *
  1405. *******************************************************************************
  1406.  
  1407.                 lda        #0
  1408.                 tax
  1409.  
  1410.                 rts
  1411.                 ENDP
  1412.  
  1413.                 EJECT
  1414. *******************************************************************************
  1415. *
  1416. InitCtlData        PROC
  1417. *
  1418. * Description:    Initialize some    data that will needs to    be handy: Get a
  1419. *    pointer    to the control record (we are supplied only    with
  1420. *    a handle), make    a local    copy of    the    control    rectangle, set
  1421. *    up a pointer to    a color    table, and move    CtlParam from a
  1422. *    Direct Page    location into an absolute location.
  1423. *
  1424. *
  1425. * Inputs:    NONE
  1426. *
  1427. * Outputs:    NONE
  1428. *
  1429. * External Refs:    NONE
  1430. *
  1431. * Entry    Points:    NONE
  1432. *
  1433. *******************************************************************************
  1434.                 with    CtlData
  1435.  
  1436. ;
  1437. ; Check    to see if the Control Manager is sending us    a 'RecSize'    call. If it
  1438. ; is, then we cannot rely on the validity of the Control handle, as    it has not
  1439. ; yet been allocated and is    essentially    garbage. Since we do not know what it
  1440. ; points to, we    don't want to read from it, as it may actually accidentally
  1441. ; point    to something dangerous,    like the IWM I/O locations!!! So if    we detect
  1442. ; a    RecSize    code, skip over    this routine.
  1443. ;
  1444.                 lda        <CtlCode                ; is this a    RecSize    call?
  1445.                 cmp        #recSize
  1446.                 beq        done                    ; yes -    skip this whole    routine
  1447.  
  1448. ;
  1449. ; Copy the value in    CtlParam into a    local location -- off of the direct    page.
  1450. ; We do    this for convenience. We may need to pass a    pointer    to CtlParam    to
  1451. ; a    toolbox    routine, but you can't do that for a direct page location. The
  1452. ; number assiciated    with a direct page location    is really an offset    off    of the
  1453. ; base specified by    the    Direct Page    register; it is    NOT    an absolute    memory
  1454. ; location.    So that    we can conveniently    use    'PushLong #location' if    we need
  1455. ; to, I    copy CtlParam to a non-direct page location.
  1456. ;
  1457.                 lda        <CtlParam
  1458.                 sta        theParam
  1459.                 lda        <CtlParam+2
  1460.                 sta        theParam+2
  1461.  
  1462.                 ldy        #2                        ; get a    handy pointer to the CtlRec
  1463.                 lda        [<theCtlHandle],y
  1464.                 sta        <CtlPtr+2
  1465.                 lda        [<theCtlHandle]
  1466.                 sta        <CtlPtr
  1467.  
  1468.                 ldy        #octlRect+6                ; copy the control rect    over to    the
  1469.                 ldx        #6                        ; local    variable.
  1470. loop            lda        [<CtlPtr],y
  1471.                 sta        myCtlRect,x
  1472.                 dey
  1473.                 dey
  1474.                 dex
  1475.                 dex
  1476.                 bpl        loop
  1477.  
  1478. ;
  1479. ; The following    values are used    by Snap2Grid. However, Snap2Grid can be
  1480. ; called with an invalid Direct    Page, so we    copy them out the control
  1481. ; record (which    is pointed to by a pointer in our Direct Page) and into
  1482. ; some absolute    locations that we can get to at    all    times.
  1483. ;
  1484.                 ldy        #oCtlGridX                ; get the X    and    Y spacings out of the
  1485.                 lda        [<CtlPtr],y                ; control record and into some local
  1486.                 sta        myCtlGridX                ; storage for easy handling.
  1487.  
  1488.                 ldy        #oCtlGridY
  1489.                 lda        [<CtlPtr],y
  1490.                 sta        myCtlGridY
  1491.  
  1492. ; Check    the    color table    pointer. If    it is non-zero,    install    it as the
  1493. ; pointer to the color table we'll be using. If not, then install a
  1494. ; pointer to a default color table.
  1495.  
  1496.                 ldy        #octlColor                ; Get the pointer to the color
  1497.                 lda        [<CtlPtr],y                ; table    in the control record.
  1498.                 sta        ColorPtr                ; Save it to a local pointer.
  1499.                 iny
  1500.                 iny
  1501.                 lda        [<CtlPtr],y
  1502.                 sta        ColorPtr+2
  1503.                 ora        ColorPtr                ; is it    a NULL pointer?
  1504.                 bne        done                    ; no, so use it.
  1505.  
  1506.                 lda        #StdColorTable            ; yes, install my own color    table.
  1507.                 sta        ColorPtr
  1508.                 lda        #^StdColorTable
  1509.                 sta        ColorPtr+2
  1510.  
  1511. done
  1512.                 rts
  1513.  
  1514.                 ENDP
  1515.  
  1516.                 EJECT
  1517. *******************************************************************************
  1518. *
  1519. SetCtlRect        PROC
  1520. *
  1521. * Description:    This routine is    called when    the    control's bounding
  1522. *    rectangle has been changed and needs to    be written back
  1523. *    out    to the control record.
  1524. *
  1525. *
  1526. * Inputs:    NONE
  1527. *
  1528. * Outputs:    NONE
  1529. *
  1530. * External Refs:    NONE
  1531. *
  1532. * Entry    Points:    NONE
  1533. *
  1534. *******************************************************************************
  1535.                 with    CtlData
  1536.  
  1537.                 ldy        #octlRect+6                ; get an offset    into the control rec.
  1538.                 ldx        #6                        ; index    to my local    record.
  1539. loop
  1540.                 lda        myCtlRect,x
  1541.                 sta        [<CtlPtr],y
  1542.                 dey
  1543.                 dey
  1544.                 dex
  1545.                 dex
  1546.                 bpl        loop
  1547.  
  1548.                 rts
  1549.  
  1550.                 ENDP
  1551.  
  1552.                 EJECT
  1553. *******************************************************************************
  1554. *
  1555. SetMyPen        PROC
  1556. *
  1557. * Description:    We want    our    control    to look    good in    both 320 and 640 mode.
  1558. *    Because    vertical lines are thinner in 640 than 320,    its    a
  1559. *    good idea to draw them doubly thick    just so    they can be
  1560. *    seen. This routine will    determine what mode    we are in and
  1561. *    adjust the pen accordingly.
  1562. *
  1563. *
  1564. * Inputs:    NONE
  1565. *
  1566. * Outputs:    NONE
  1567. *
  1568. * External Refs:    NONE
  1569. *
  1570. * Entry    Points:    NONE
  1571. *
  1572. *******************************************************************************
  1573.                 with    CtlData
  1574.  
  1575.                 pha                                ; we base pen width    on the MasterSCB
  1576.                 _GetMasterSCB
  1577.                 pla
  1578.                 and        #$0080                    ; check    the    mode bit
  1579.                 beq        pen320                    ; we are in    320    mode - go push a 1
  1580.  
  1581.                 PushWord #2                        ; in 640 mode -    push on    a 2    width
  1582.                 bra        setpn
  1583.  
  1584. pen320            PushWord #1                        ; in 320 mode -    push on    a 1    width
  1585.  
  1586. setpn                                            ; width    is 1 or    2
  1587.                 PushWord #1                        ; Height is    always 1
  1588.                 _SetPenSize
  1589.  
  1590.                 rts
  1591.                 ENDP
  1592.  
  1593.                 EJECT
  1594. *******************************************************************************
  1595. *
  1596. CalcCorners        PROC
  1597. *
  1598. * Description:    This routine calculates    the    rectangles for all of the
  1599. *    little knobs that are used to grow the control.    They are
  1600. *    stored locally - not with the control record - and so need
  1601. *    to be calculated every time    we need    to check for hits or
  1602. *    to draw    the    control.
  1603. *
  1604. *
  1605. * Inputs:    NONE
  1606. *
  1607. * Outputs:    knobXXX, FrameHeight, FrameWidth variables are initialized.
  1608. *
  1609. * External Refs:    NONE
  1610. *
  1611. * Entry    Points:    NONE
  1612. *
  1613. *******************************************************************************
  1614.                 with    CtlData
  1615.  
  1616. top                equ        0                        ; alias    these to something a little
  1617. left            equ        2                        ; more descriptive.
  1618. bottom            equ        4
  1619. right            equ        6
  1620.  
  1621. ; Get the size of the knobs. The height    and    width are stored in    the    CtlValue
  1622. ; field    in a packed    format.    This unpacks them and stores them locally for
  1623. ; ease of access.
  1624.  
  1625.                 ldy        #octlValue
  1626.                 lda        [<CtlPtr],y
  1627.                 and        #$00FF
  1628.                 sta        FrameHeight
  1629.                 lda        [<CtlPtr],y
  1630.                 xba
  1631.                 and        #$00FF
  1632.                 sta        FrameWidth
  1633.  
  1634. ;
  1635. ; We "assembly line" the initialization    of the knob    rectangles.    Instead
  1636. ; of calculating just one knob at a    time, we do    a few of them all at the
  1637. ; same time. Here we initialize    the    tops and bottoms of    the    3 top knobs.
  1638.  
  1639.                 lda        myCtlRect+top
  1640.                 sta        knobUL+top
  1641.                 sta        knobTop+top
  1642.                 sta        knobUR+top
  1643.                 clc
  1644.                 adc        FrameHeight
  1645.                 sta        knobUL+bottom
  1646.                 sta        knobTop+bottom
  1647.                 sta        knobUR+bottom
  1648.  
  1649. ;
  1650. ; Initialize the lefts and rights of the three left    knobs.
  1651. ;
  1652.                 lda        myCtlRect+left
  1653.                 sta        knobUL+left
  1654.                 sta        knobLeft+left
  1655.                 sta        knobLL+left
  1656.                 clc
  1657.                 adc        FrameWidth
  1658.                 sta        knobUL+right
  1659.                 sta        knobLeft+right
  1660.                 sta        knobLL+right
  1661.  
  1662. ;
  1663. ; Initialize the tops and bottoms of the three bottom knobs.
  1664. ;
  1665.                 lda        myCtlRect+bottom
  1666.                 sta        knobLL+bottom
  1667.                 sta        knobBottom+bottom
  1668.                 sta        knobLR+bottom
  1669.                 sec
  1670.                 sbc        FrameHeight
  1671.                 sta        knobLL+top
  1672.                 sta        knobBottom+top
  1673.                 sta        knobLR+top
  1674.  
  1675. ;
  1676. ; Initialize the lefts and rights of the three right knobs.
  1677. ;
  1678.                 lda        myCtlRect+right
  1679.                 sta        knobUR+right
  1680.                 sta        knobRight+right
  1681.                 sta        knobLR+right
  1682.                 sec
  1683.                 sbc        FrameWidth
  1684.                 sta        knobUR+left
  1685.                 sta        knobRight+left
  1686.                 sta        knobLR+left
  1687.  
  1688. ;
  1689. ; At this point, the 4 corner knobs    have been completely initialized.
  1690. ; If we    are    going to be    using the edge knobs, then we'll have to do
  1691. ; some extra math. However,    if we aren't, then we'll skip over the
  1692. ; math.
  1693.  
  1694.                 ldy        #octlFlag
  1695.                 lda        [<CtlPtr],y
  1696.                 and        #knobEdgeMask
  1697.                 beq        done
  1698.  
  1699. ; Do extra setup for edge knobs
  1700. ;
  1701. ; First, get top and bottom    coordinates    for    the    side edges:
  1702. ;
  1703. ;      top =    (myCtlRect.top + myCtlRect.bottom -    FrameHeight)/2
  1704. ;      bot =    (myCtlRect.top + myCtlRect.bottom +    FrameHeight)/2
  1705.  
  1706.                 clc
  1707.                 lda        myCtlRect+top
  1708.                 adc        myCtlRect+bottom
  1709.                 pha
  1710.                 adc        FrameHeight
  1711.                 lsr        a
  1712.                 sta        knobLeft+bottom
  1713.                 sta        knobRight+bottom
  1714.                 pla
  1715.                 sec
  1716.                 sbc        FrameHeight
  1717.                 lsr        a
  1718.                 sta        knobLeft+top
  1719.                 sta        knobRight+top
  1720.  
  1721. ;
  1722. ; Now perform similar calculations for the left    and    right sides
  1723. ; of the top and bottom    edge knobs.
  1724. ;
  1725.                 clc
  1726.                 lda        myCtlRect+left
  1727.                 adc        myCtlRect+right
  1728.                 pha
  1729.                 adc        FrameWidth
  1730.                 lsr        a
  1731.                 sta        knobTop+right
  1732.                 sta        knobBottom+right
  1733.                 pla
  1734.                 sec
  1735.                 sbc        FrameWidth
  1736.                 lsr        a
  1737.                 sta        knobTop+left
  1738.                 sta        knobBottom+left
  1739.  
  1740. done
  1741.                 rts
  1742.                 ENDP
  1743.  
  1744.                 EJECT
  1745. *******************************************************************************
  1746. *
  1747. Snap2Grid        PROC
  1748. *
  1749. * Description:    This control defproc lets the application optionally create
  1750. *    an invisible grid based    on local coordinates. When this    is
  1751. *    done, the 4    corners    of the control are always aligned to
  1752. *    the    coordinates    of this    grid. This occurs when we drag or
  1753. *    resize the control,    or call    MoveControl. Snap2Grip is the
  1754. *    routine    that ensures we    are    on the grid.
  1755. *
  1756. *
  1757. * Inputs:    A =    low    word of    pointer    to rectangle to    fix
  1758. *    X =    high word
  1759. *
  1760. * Outputs:    rectangle is modified in place.
  1761. *
  1762. * External Refs:    NONE
  1763. *
  1764. * Entry    Points:    NONE
  1765. *
  1766. *******************************************************************************
  1767.                 with    CtlData
  1768.  
  1769. oldD            equ        1
  1770. oldB            equ        oldD+2
  1771. rectPtr            equ        oldB+1
  1772.  
  1773. ;
  1774. ; We are going to use a    local direct page here.    This is    because    Snap2Grid is
  1775. ; called by    my routine that    draws the control's recangle as it is being
  1776. ; dragged. When    that happens, we are not using our normal direct page, and
  1777. ; hence    can't use any of the values or work locations there. So we set up
  1778. ; another one with it's own workspace.
  1779. ;
  1780.                 phx                                ; save the pointer to the rectangle
  1781.                 pha
  1782.  
  1783.                 phb                                ; save the caller's data bank register
  1784.                 phd                                ; save the caller'd direct page reg.
  1785.  
  1786.                 phk                                ; switch data bank to program bank
  1787.                 plb
  1788.  
  1789.                 tsc                                ; switch direct    page to    stack pointer
  1790.                 tcd
  1791.  
  1792.  
  1793. ;
  1794. ; WhchGridYX is    used to    help generalize    this routine. We support different
  1795. ; spacings in the X    and    Y directions of    the    grid. As we    loop through all 4
  1796. ; coordinates of the rectangle,    we want    to make    sure that we are using the
  1797. ; correct spacing. 'whichGridYX' holds flags that tell us when to use X    and
  1798. ; when to use Y    spacing    (0 = use Y spacing;    1 =    use    X spacing).
  1799. ;
  1800.                 lda        #%0101                    ; Set up some indices into GridYX
  1801.                 sta        whichGridYX
  1802.  
  1803. ;
  1804. ; Fix the coordinates by using the following method:
  1805. ;
  1806. ;  1. Get the difference between the coordinate    we are examining and
  1807. ;      the next lowest grid location:
  1808. ;
  1809. ;           z = coordinate mod GridSize
  1810. ;
  1811. ;  2. Z    tells how far away from    the    next lowest    grid line
  1812. ;      the coordinate we    are    looking    at is, so subtracting that
  1813. ;      value    will put the coordinate    on the grid.
  1814. ;
  1815. ;           coordinate := coordinate    - z
  1816. ;
  1817. ;  3. However, this    is simply truncating, and I    don't like the
  1818. ;      way that feels when resizing the control.    So lets    add    an
  1819. ;      instruction so that it ROUNDS    instead.
  1820. ;
  1821. ;           if z    > GridSize/2 then
  1822. ;                coordinate := coordinate + GridSize
  1823. ;
  1824.  
  1825.                 ldy        #6                        ; init our loop    index
  1826. Loop
  1827.                 sty        YSave
  1828.  
  1829.                 lda        whichGridYX                ; do we    now    use    X or Y grid    spacing?
  1830.                 and        #%0001
  1831.                 beq        UseY
  1832.                 lda        myCtlGridX
  1833.                 bra        UseIt
  1834. UseY
  1835.                 lda        myCtlGridY
  1836.  
  1837. ; we now have the gridsize in the Acc
  1838. UseIt
  1839.                 cmp        #2                        ; Is it    0 or 1?    If so, then    skip over
  1840.                 blt        ShortCircuit            ;    dividing routine.
  1841.                 sta        GridSize                ; save this    for    the    divide later.
  1842.  
  1843.                 pha                                ; push space on    stack for the result
  1844.                 pha                                ; of the divide    we are going to    do.
  1845.  
  1846.                 lda        [<rectPtr],y            ; push on the coordinate we    are
  1847.                 pha                                ;    adjusting as the Dividend
  1848.                 PushWord GridSize                ; push this    on as the divisor
  1849.                 _UDivide                        ; unsigned divide
  1850.                 pla                                ; quotient - we    don't want it.
  1851.                 PullWord Remainder                ; remainder    is 'z' - Keep it!
  1852.  
  1853.                 ldy        YSave                    ; get my coordinate    index back.
  1854.                 lda        [<rectPtr],y            ; get the coordinate to    change
  1855.                 sec
  1856.                 sbc        Remainder                ; change it
  1857.                 sta        [<rectPtr],y            ; save it back out
  1858.  
  1859.                 lda        GridSize                ; Make a GridSize/2
  1860.                 lsr        a
  1861.                 cmp        Remainder                ; is remainder < GridSize/2?
  1862.                 bge        ShortCircuit            ; yes -    so we're done
  1863.                 lda        [<rectPtr],y            ; no - so bump the coordinate
  1864.                 clc
  1865.                 adc        GridSize
  1866.                 sta        [<rectPtr],y
  1867.  
  1868. ShortCircuit    lsr        whichGridYX                ; move the next    index into place
  1869.                 dey                                ; bump down    to the next    coordinate
  1870.                 dey                                ;    of the rectangle.
  1871.                 bpl        Loop
  1872.  
  1873. Exit
  1874.                 pld                                ; restore caller's Direct Page reg.
  1875.                 plb                                ; restore data bank    register
  1876.                 pla                                ; remove rect pointer
  1877.                 pla
  1878.                 rts                                ; all done - go    bye-bye
  1879.  
  1880. whichGridYX        ds.b    2
  1881. YSave            ds.b    2
  1882. Remainder        ds.b    2
  1883. GridSize        ds.b    2
  1884.  
  1885.                 ENDP
  1886.  
  1887.                 EJECT
  1888. *******************************************************************************
  1889. *
  1890. FindPart        PROC
  1891. *
  1892. * Description:    This routine is    called to find out exactly which part of
  1893. *    the    control    we clicked in. It first    checks to see if we
  1894. *    clicked    in any of the grow knobs. If so, then it returns
  1895. *    an 'internal partcode' telling the calling routine which
  1896. *    knob was clicked in. If    a knob wasn't clicked in, a check
  1897. *    is made    to see if we clicked on    the    frame. If we are
  1898. *    allowed    to click in    the    interior, a    check is made to see
  1899. *    if we clicked there, too.
  1900. *
  1901. *
  1902. * Inputs:    NONE
  1903. *
  1904. * Outputs:    A =    internal partcode of part hit (1-10)
  1905. *
  1906. * External Refs:
  1907.                 import    CalcCorners
  1908. *
  1909. * Entry    Points:
  1910.                 entry    TestFrame                ; called by    myTestCtl
  1911. *
  1912. *******************************************************************************
  1913.                 with    CtlData
  1914.  
  1915.                 jsr        CalcCorners
  1916.  
  1917. ;
  1918. ; We first check to    see    if the mouse was clicked in    any    of the knobs. We do
  1919. ; this by assuming a knob was clicked in, and then checking    to see if that was
  1920. ; true.    If so, we leave    here with the partcode we assumed. If not, we loop
  1921. ; through and check    all    of the other knobs.    If none    of the knobs was clicked
  1922. ; in, we see if    the    frame was clicked on.
  1923.  
  1924.                 ldx        #LeftPart                ; get last knob's part code
  1925.                 ldy        #7*8                    ; point    to last    knob's rect
  1926.  
  1927. loop
  1928.                 phx                                ; save partcode    we're checking for...
  1929.                 phy                                ; and the rect's pointer
  1930.  
  1931.                 pha                                ; space    for    _PtInRect result
  1932.                 PushLong #theParam                ; push on the point    to check
  1933.                 lda        #^knobUL                ; create a pointer to the rect
  1934.                 pha
  1935.                 clc                                ; Bumping just the low byte    is OK
  1936.                 tya                                ;    unless the GS suddenly lets
  1937.                 adc        #knobUL                    ;    code segments cross    bank
  1938.                 pha                                ;    boundaries
  1939.                 _PtInRect
  1940.                 pla                                ; get result of    PtInRect
  1941.                 ply                                ; retrieve rectangle index
  1942.                 plx                                ; retrieve part    code
  1943.                 cmp        #0                        ; did we score a hit?
  1944.                 bne        InKnob                    ; yes, return with the part    code
  1945.                 dex                                ; move down    to next    partcode
  1946.                 sec                                ; move down    to next    rectangle
  1947.                 tya
  1948.                 sbc        #8
  1949.                 tay
  1950.                 bpl        loop                    ; keep going until rect    index <    0
  1951.  
  1952.                 bra        TestFrame                ; not in knobs - try frame
  1953.  
  1954. ;
  1955. ; We just scored a hit on one of the knobs,    and    X holds    the    knob number.
  1956. ; However, the application may not have    corner or edge knobs active. So
  1957. ; if we    clicked    on an inactive knob, have to check for that    and    return
  1958. ; 'inFrame'    instead    of a knob partcode.
  1959. ;
  1960. InKnob
  1961.                 ldy        #octlFlag                ; are corner knobs active?
  1962.                 lda        [<CtlPtr],y
  1963.                 and        #knobCornerMask
  1964.                 bne        ckEdge                    ; yes -    so pass    this code on.
  1965.  
  1966.                 txa                                ; Corners not allowed. Did we hit one?
  1967.                 lsr        a
  1968.                 bcs        RetFramePart            ; yes, so return click on Frame    instead
  1969.  
  1970. ckEdge
  1971.                 ldy        #octlFlag                ; are edge knobs active?
  1972.                 lda        [<CtlPtr],y
  1973.                 and        #knobEdgeMask
  1974.                 bne        done                    ; yes -    so return this code
  1975.  
  1976.                 txa                                ; Edges    not    allowed. Did we    hit    one?
  1977.                 lsr        a
  1978.                 bcs        TestFrame                ; no, so pass this code    on.
  1979. RetFramePart
  1980.                 ldx        #FramePart                ; yes, so return click on Frame    instead
  1981. done
  1982.                 txa                                ; put the part code    in the Acc
  1983.                 rts
  1984.  
  1985. TestFrame
  1986.  
  1987. ; First    test to    see    if it is within    the    Control's rectangle. It should
  1988. ; be, but let's check anyway...
  1989.  
  1990.                 pha
  1991.                 PushLong #theParam
  1992.                 PushLong #myCtlRect
  1993.                 _PtInRect
  1994.                 pla
  1995.                 beq        NotInFrame                ; no in    the    frame. Signal noPart
  1996.  
  1997. ; Now see if we    differentiate between the frame    and    the    interior
  1998.  
  1999.                 ldy        #octlFlag
  2000.                 lda        [<CtlPtr],y
  2001.                 and        #dragIntMask
  2002.                 bne        RetFramePart            ; nope - everything    drags
  2003.  
  2004. ; Yes we do. Now see if    we hit the frame fair and square. Inset    the
  2005. ; control's bounding rectangle by the size of the knobs that are on
  2006. ; it to    create an inner    rectangle. If we fall between those    two
  2007. ; rectangles, then I say that you have landed on the frame.    If we
  2008. ; got this far,    then we    know that we are within    the    outer rectangle.
  2009. ; Now see if we    are    outside    of the inner rectangle.
  2010.  
  2011.                 ldx        #6                        ; make a copy of the control rect
  2012. CopyLoop        lda        myCtlRect,x                ; so that we can reduce    it.
  2013.                 sta        innerRect,x
  2014.                 dex
  2015.                 dex
  2016.                 bpl        CopyLoop
  2017.  
  2018.                 PushLong #innerRect                ; push on pointer to the rect to inset
  2019.                 PushWord FrameWidth                ; push on the amounts to inset it by
  2020.                 PushWord FrameHeight            ; (these vals inited by    CalcCorners)
  2021.                 _InsetRect
  2022.  
  2023.                 pha                                ; see if we    are    outside    of the inner
  2024.                 PushLong #theParam                ; rectangle
  2025.                 PushLong #innerRect
  2026.                 _PtInRect
  2027.  
  2028.                 pla                                ; check    the    result
  2029.                 beq        RetFramePart            ; we were between rects!
  2030.  
  2031. NotInFrame        lda        #noPart                    ; Not *exactly*    on the frame.
  2032.                 rts
  2033.  
  2034. innerRect        ds.b    8
  2035.  
  2036.                 ENDP
  2037.  
  2038.                 End
  2039.  
  2040.